﻿using System;
using System.Collections.Generic;
using System.Linq;

using TemporaryConsoleApplication.Opentao.NotificationService.AdminService;
using TemporaryConsoleApplication.Opentao.NotificationService.ClientService;

namespace TemporaryConsoleApplication
{
    /// <summary>
    /// All hope abandon, ye who enter in.
    /// Terryfying govnocode lies ahead.
    /// </summary>
    internal static class Program
    {
        private static readonly AdminServiceClient AdminServiceClient = new AdminServiceClient();
        private static readonly ClientServiceClient ClientServiceClient = new ClientServiceClient();

        private static int _entriesToDisplay;

        private static void Main()
        {
            Init();
            MainMenu();
        }

        private static void Init()
        {
            Console.Title = "Opentao Notification Service";

            Console.BufferHeight = Console.WindowHeight;
            Console.BufferWidth = Console.WindowWidth;

            _entriesToDisplay = 10;
        }

        private static void MainMenu()
        {
            while( true ) {
                Console.Clear();

                Console.WriteLine( Environment.NewLine );
                Console.WriteLine( "[1] Отправить сообщение" );
                Console.WriteLine( "[2] Просмотреть список получателей" );
                Console.WriteLine( "[3] Просмотреть уровни важности" );
                Console.WriteLine( "[4] Просмотреть типы событий" );

                Console.WriteLine( "[Esc] Выйти из приложения" );

                var key = Console.ReadKey( true ).Key;

                if( key == ConsoleKey.D2 ||
                    key == ConsoleKey.NumPad2 )
                    RecipientsList();

                if( key == ConsoleKey.D3 ||
                    key == ConsoleKey.NumPad3 )
                    ImportanceLevelsList();

                if( key == ConsoleKey.D4 ||
                    key == ConsoleKey.NumPad4 )
                    EventTypesList();

                if( key == ConsoleKey.D1 ||
                    key == ConsoleKey.NumPad1 )
                    ShowSendMessageDialog();

                if( key == ConsoleKey.Escape )
                    Environment.Exit( 0 );
            }
        }

        private static void EventTypesList()
        {
            while( true ) {
                Console.Clear();

                Console.WriteLine(
                    Environment.NewLine + "[Esc] Назад, [Индекс] Детали, [Space] Создать" + Environment.NewLine );

                var eventTypes = AdminServiceClient.GetEventTypes( new GetEventTypesRequest() ).GetEventTypesResult;
                var indexedEventTypes = new Dictionary<char, EventTypeDTO>();

                for( var i = 0; i < eventTypes.Count; i++ )
                    indexedEventTypes.Add( ( char ) ( 'A' + i ), eventTypes[ i ] );

                foreach( var indexedEventType in indexedEventTypes ) {
                    Console.WriteLine( "[{0}] {1}", indexedEventType.Key, indexedEventType.Value.Title );
                }

                var key = Console.ReadKey( true );

                if( indexedEventTypes.Keys.Contains( char.ToUpper( key.KeyChar ) ) )
                    ManageEventTypeMenu( indexedEventTypes[ char.ToUpper( key.KeyChar ) ] );

                if( key.Key ==
                    ConsoleKey.Escape )
                    MainMenu();

                if( key.Key ==
                    ConsoleKey.Spacebar )
                    CreateEventTypeDialog();
            }
        }

        private static void CreateEventTypeDialog()
        {
            Console.Clear();

            Console.WriteLine( "Введите название:" );
            var title = Console.ReadLine();

            AdminServiceClient.CreateEventType( new CreateEventTypeRequest( title ) );
            EventTypesList();
        }

        private static void ManageEventTypeMenu( EventTypeDTO eventType )
        {
            while( true ) {
                Console.Clear();

                Console.WriteLine(
                    Environment.NewLine + "[Esc] Назад\n[T] Сменить название\n[Del] Удалить" + Environment.NewLine );

                Console.WriteLine( "Название: " + eventType.Title );

                var key = Console.ReadKey( true );

                if( key.Key ==
                    ConsoleKey.Escape )
                    EventTypesList();

                if( key.Key ==
                    ConsoleKey.T ) {
                    AdminServiceClient.UpdateEventType(
                        new UpdateEventTypeRequest( eventType.Id, ChangeValueDialog() ) );
                    ManageEventTypeMenu(
                        AdminServiceClient.GetEventTypes( new GetEventTypesRequest() ).GetEventTypesResult.Single(
                            et => et.Id == eventType.Id ) );
                }

                if( key.Key ==
                    ConsoleKey.Delete ) {
                    AdminServiceClient.DeleteEventType( new DeleteEventTypeRequest( eventType.Id ) );
                    EventTypesList();
                }
            }
        }

        private static void ImportanceLevelsList()
        {
            while( true ) {
                Console.Clear();

                Console.WriteLine(
                    Environment.NewLine + "[Esc] Назад, [Индекс] Детали, [Space] Создать" + Environment.NewLine );

                var importanceLevels =
                    AdminServiceClient.GetImportanceLevels( new GetImportanceLevelsRequest() ).GetImportanceLevelsResult;
                var indexedImportanceLevels = new Dictionary<char, ImportanceLevelDTO>();

                for( var i = 0; i < importanceLevels.Count; i++ )
                    indexedImportanceLevels.Add( ( char ) ( 'A' + i ), importanceLevels[ i ] );

                foreach( var indexedImportanceLevel in indexedImportanceLevels ) {
                    Console.WriteLine( "[{0}] {1}", indexedImportanceLevel.Key, indexedImportanceLevel.Value.Title );
                }

                var key = Console.ReadKey( true );

                if( indexedImportanceLevels.Keys.Contains( char.ToUpper( key.KeyChar ) ) )
                    ManageImportanceLevelMenu( indexedImportanceLevels[ char.ToUpper( key.KeyChar ) ] );

                if( key.Key ==
                    ConsoleKey.Escape )
                    MainMenu();

                if( key.Key ==
                    ConsoleKey.Spacebar )
                    CreateImportanceLevelDialog();
            }
        }

        private static void CreateImportanceLevelDialog()
        {
            Console.Clear();

            Console.WriteLine( "Введите название:" );
            var title = Console.ReadLine();
            Console.WriteLine( "Использовать электронную почту? [y/n]" );
            bool useEmail;

            while( true ) {
                var key = Console.ReadKey( true ).Key;
                if( key == ConsoleKey.Y ) {
                    useEmail = true;
                    break;
                }
                if( key == ConsoleKey.N ) {
                    useEmail = false;
                    break;
                }
            }

            Console.WriteLine( "Использовать SMS? [y/n]" );

            bool useSMS;

            while( true ) {
                var key = Console.ReadKey( true ).Key;
                if( key == ConsoleKey.Y ) {
                    useSMS = true;
                    break;
                }
                if( key == ConsoleKey.N ) {
                    useSMS = false;
                    break;
                }
            }

            AdminServiceClient.CreateImportanceLevel( new CreateImportanceLevelRequest( title, useEmail, useSMS ) );

            ImportanceLevelsList();
        }

        private static void ManageImportanceLevelMenu( ImportanceLevelDTO importanceLevel )
        {
            while( true ) {
                Console.Clear();

                Console.WriteLine(
                    Environment.NewLine +
                    "[Esc] Назад\n[T] Сменить название\n[E] Переключить использование эл.почты\n[P] Переключить использование SMS\n[Del] Удалить" +
                    Environment.NewLine );

                Console.WriteLine( "Название: " + importanceLevel.Title );
                Console.WriteLine( "Использовать электронную почту: " + importanceLevel.UseEmail );
                Console.WriteLine( "Использовать SMS: " + importanceLevel.UsePhone );

                var key = Console.ReadKey( true );

                if( key.Key ==
                    ConsoleKey.T ) {
                    AdminServiceClient.UpdateImportanceLevel(
                        new UpdateImportanceLevelRequest(
                            importanceLevel.Id, ChangeValueDialog(), importanceLevel.UseEmail, importanceLevel.UsePhone ) );
                    ManageImportanceLevelMenu(
                        AdminServiceClient.GetImportanceLevels( new GetImportanceLevelsRequest() ).
                            GetImportanceLevelsResult.Single( il => il.Id == importanceLevel.Id ) );
                }

                if( key.Key ==
                    ConsoleKey.E ) {
                    AdminServiceClient.UpdateImportanceLevel(
                        new UpdateImportanceLevelRequest(
                            importanceLevel.Id,
                            importanceLevel.Title,
                            !importanceLevel.UseEmail,
                            importanceLevel.UsePhone ) );
                    ManageImportanceLevelMenu(
                        AdminServiceClient.GetImportanceLevels( new GetImportanceLevelsRequest() ).
                            GetImportanceLevelsResult.Single( il => il.Id == importanceLevel.Id ) );
                }

                if( key.Key ==
                    ConsoleKey.P ) {
                    AdminServiceClient.UpdateImportanceLevel(
                        new UpdateImportanceLevelRequest(
                            importanceLevel.Id,
                            importanceLevel.Title,
                            importanceLevel.UseEmail,
                            !importanceLevel.UsePhone ) );
                    ManageImportanceLevelMenu(
                        AdminServiceClient.GetImportanceLevels( new GetImportanceLevelsRequest() ).
                            GetImportanceLevelsResult.Single( il => il.Id == importanceLevel.Id ) );
                }

                if( key.Key ==
                    ConsoleKey.Escape )
                    ImportanceLevelsList();

                if( key.Key ==
                    ConsoleKey.Delete ) {
                    AdminServiceClient.DeleteImportanceLevel( new DeleteImportanceLevelRequest( importanceLevel.Id ) );
                    ImportanceLevelsList();
                }
            }
        }

        private static void RecipientsList(
            bool isSortOrderAscending = true,
            string sortProperty = "Name",
            int pageNumber = 0 )
        {
            while( true ) {
                Console.Clear();
                Console.WriteLine(
                    Environment.NewLine +
                    "[Esc] Назад, [Up] Сменить направление сортировки, [Down] Сменить поле сортировки\n[Индекс] Детали, [Space] Добавить нового получателя" +
                    Environment.NewLine );

                var recipients =
                    AdminServiceClient.GetRecipients(
                        new GetRecipientsRequest( isSortOrderAscending, sortProperty, _entriesToDisplay, pageNumber ) ).
                        GetRecipientsResult;
                var indexedRecipients = new Dictionary<char, RecipientDTO>();

                for( var i = 0; i < recipients.Count; i++ )
                    indexedRecipients.Add( ( char ) ( 'A' + i ), recipients[ i ] );

                foreach( var indexedRecipient in indexedRecipients ) {
                    Console.WriteLine(
                        "[{0}] {1}: {2} | {3}",
                        indexedRecipient.Key,
                        indexedRecipient.Value.Name,
                        indexedRecipient.Value.Email,
                        indexedRecipient.Value.Phone );
                }

                var pagesCount =
                    ( AdminServiceClient.GetRecipientsCount( new GetRecipientsCountRequest() ).GetRecipientsCountResult +
                      _entriesToDisplay - 1 )/_entriesToDisplay;
                var pagingHint = string.Format( "{0}({1})", pageNumber + 1, pagesCount );
                var canMoveBack = pageNumber != 0;
                var canMoveForward = ( pageNumber + 1 ) < pagesCount;

                if( canMoveBack )
                    pagingHint = string.Concat( "< Предыдущая страница ", pagingHint );

                if( canMoveForward )
                    pagingHint = string.Concat( pagingHint, " Следующая страница >" );

                Console.WriteLine( Environment.NewLine + pagingHint );

                var key = Console.ReadKey( true );

                if( key.Key == ConsoleKey.LeftArrow && canMoveBack )
                    RecipientsList( isSortOrderAscending, sortProperty, pageNumber - 1 );

                if( key.Key == ConsoleKey.RightArrow && canMoveForward )
                    RecipientsList( isSortOrderAscending, sortProperty, pageNumber + 1 );

                if( key.Key ==
                    ConsoleKey.UpArrow )
                    RecipientsList( !isSortOrderAscending, sortProperty );

                if( key.Key ==
                    ConsoleKey.DownArrow ) {
                    RecipientsList(
                        sortProperty: sortProperty == "Name"
                                          ? "Email"
                                          : "Name",
                        isSortOrderAscending: isSortOrderAscending );
                }

                if( key.Key ==
                    ConsoleKey.Spacebar )
                    CreateNewRecipientDialog();

                if( key.Key ==
                    ConsoleKey.Escape )
                    MainMenu();

                if( indexedRecipients.Keys.Contains( char.ToUpper( key.KeyChar ) ) )
                    ManageRecipientMenu( indexedRecipients[ char.ToUpper( key.KeyChar ) ] );
            }
        }

        private static void CreateNewRecipientDialog()
        {
            Console.Clear();

            Console.WriteLine( "Введите E-mail адрес:" );
            var email = Console.ReadLine();

            Console.WriteLine( "Введите номер телефона:" );
            var phone = Console.ReadLine();

            Console.WriteLine( "Введите имя получателя:" );
            var name = Console.ReadLine();

            AdminServiceClient.CreateRecipient( new CreateRecipientRequest( email, phone, name ) );

            RecipientsList();
        }

        private static void ManageRecipientMenu( RecipientDTO recipient )
        {
            while( true ) {
                Console.Clear();
                Console.WriteLine(
                    Environment.NewLine +
                    "[Esc] Назад\n[N] Сменить имя\n[E] Сменить e-mail\n[P] Сменить номер телефона\n[S] Управление подписками\n[Del] Удалить получателя" +
                    Environment.NewLine );

                Console.WriteLine( "Имя: " + recipient.Name );
                Console.WriteLine( "Адрес электронной почты: " + recipient.Email );
                Console.WriteLine( "Номер телефона: " + recipient.Phone );

                Console.WriteLine( Environment.NewLine );
                Console.WriteLine( "Подписки:" );

                foreach( var subscription in recipient.Subscriptions ) {
                    Console.WriteLine( subscription.Title );
                }

                var key = Console.ReadKey( true );

                if( key.Key ==
                    ConsoleKey.Delete ) {
                    AdminServiceClient.DeleteRecipient( new DeleteRecipientRequest( recipient.Id ) );
                    RecipientsList();
                }

                if( key.Key ==
                    ConsoleKey.N ) {
                    AdminServiceClient.UpdateRecipient(
                        new UpdateRecipientRequest(
                            recipient.Id, recipient.Email, recipient.Phone, ChangeValueDialog() ) );
                    ManageRecipientMenu(
                        AdminServiceClient.GetRecipient( new GetRecipientRequest( recipient.Id ) ).GetRecipientResult );
                }

                if( key.Key ==
                    ConsoleKey.E ) {
                    AdminServiceClient.UpdateRecipient(
                        new UpdateRecipientRequest( recipient.Id, ChangeValueDialog(), recipient.Phone, recipient.Name ) );
                    ManageRecipientMenu(
                        AdminServiceClient.GetRecipient( new GetRecipientRequest( recipient.Id ) ).GetRecipientResult );
                }

                if( key.Key ==
                    ConsoleKey.P ) {
                    AdminServiceClient.UpdateRecipient(
                        new UpdateRecipientRequest( recipient.Id, recipient.Email, ChangeValueDialog(), recipient.Name ) );
                    ManageRecipientMenu(
                        AdminServiceClient.GetRecipient( new GetRecipientRequest( recipient.Id ) ).GetRecipientResult );
                }

                if( key.Key ==
                    ConsoleKey.S )
                    ManageSubscriptions( recipient );

                if( key.Key ==
                    ConsoleKey.Escape )
                    RecipientsList();
            }
        }

        private static void ManageSubscriptions( RecipientDTO recipient )
        {
            while( true ) {
                Console.Clear();

                Console.WriteLine(
                    Environment.NewLine + "[Esc] Назад, [Space] добавить новую подписку, [Индекс] удалить подписку" +
                    Environment.NewLine );
                var indexedSubscriptions = new Dictionary<char, EventTypeDTO>();

                for( var i = 0; i < recipient.Subscriptions.Count; i++ )
                    indexedSubscriptions.Add( ( char ) ( 'A' + i ), recipient.Subscriptions.ToList()[ i ] );

                foreach( var indexedSubscription in indexedSubscriptions ) {
                    Console.WriteLine( "[{0}] {1}", indexedSubscription.Key, indexedSubscription.Value.Title );
                }

                var key = Console.ReadKey( true );

                if( indexedSubscriptions.Keys.Contains( char.ToUpper( key.KeyChar ) ) ) {
                    AdminServiceClient.UnSubscribeRecipient(
                        new UnSubscribeRecipientRequest(
                            recipient.Id, indexedSubscriptions[ char.ToUpper( key.KeyChar ) ].Id ) );
                    ManageSubscriptions(
                        AdminServiceClient.GetRecipient( new GetRecipientRequest( recipient.Id ) ).GetRecipientResult );
                }

                if( key.Key ==
                    ConsoleKey.Escape )
                    ManageRecipientMenu(
                        AdminServiceClient.GetRecipient( new GetRecipientRequest( recipient.Id ) ).GetRecipientResult );

                if( key.Key ==
                    ConsoleKey.Spacebar )
                    Subscribe( recipient );
            }
        }

        private static void Subscribe( RecipientDTO recipient )
        {
            while( true ) {
                Console.Clear();

                Console.WriteLine( Environment.NewLine + "[Esc] Назад, [Индекс] Подписать" + Environment.NewLine );
                var availableSubscriptions =
                    AdminServiceClient.GetEventTypes( new GetEventTypesRequest() ).GetEventTypesResult.Where(
                        et => et.Subscribers.All( s => s.Id != recipient.Id ) );

                var indexedSubscriptions = new Dictionary<char, EventTypeDTO>();

                for( var i = 0; i < availableSubscriptions.Count(); i++ )
                    indexedSubscriptions.Add( ( char ) ( 'A' + i ), availableSubscriptions.ToList()[ i ] );

                foreach( var indexedSubscription in indexedSubscriptions ) {
                    Console.WriteLine( "[{0}] {1}", indexedSubscription.Key, indexedSubscription.Value.Title );
                }
                var key = Console.ReadKey( true );

                if( indexedSubscriptions.Keys.Contains( char.ToUpper( key.KeyChar ) ) ) {
                    AdminServiceClient.SubscribeRecipient(
                        new SubscribeRecipientRequest(
                            recipient.Id, indexedSubscriptions[ char.ToUpper( key.KeyChar ) ].Id ) );
                }

                if( key.Key ==
                    ConsoleKey.Escape )
                    ManageSubscriptions(
                        AdminServiceClient.GetRecipient( new GetRecipientRequest( recipient.Id ) ).GetRecipientResult );
            }
        }

        private static string ChangeValueDialog()
        {
            Console.Clear();
            Console.WriteLine( "Введите новое значение:" );
            return Console.ReadLine();
        }

        private static void ShowSendMessageDialog()
        {
            Console.Clear();

            Console.WriteLine( "Введите уровень важности:" );
            var importanceLevel = Console.ReadLine();
            Console.WriteLine( Environment.NewLine );

            Console.WriteLine( "Введите тип события:" );
            var eventType = Console.ReadLine();
            Console.WriteLine( Environment.NewLine );

            Console.WriteLine( "Введите текст сообщения:" );
            var messageText = Console.ReadLine();
            Console.WriteLine( Environment.NewLine );

            ClientServiceClient.SendMessage( new SendMessageRequest( importanceLevel, eventType, messageText ) );
        }
    }
}